/* *******************************************************************************
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 * 4. The source and compiled code may only be used on Energy Micro "EFM32"
 *    microcontrollers and "EFR4" radios.
 *
 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
 * obligation to support this Software. Energy Micro AS is providing the
 * Software "AS IS", with no express or implied warranties of any kind,
 * including, but not limited to, any implied warranties of merchantability
 * or fitness for any particular purpose or warranties against infringement
 * of any proprietary rights of a third party.
 *
 * Energy Micro AS will not be liable for any consequential, incidental, or
 * special damages, or any other relief, or for any claim by any third party,
 * arising from your use of this Software.
 *
 *****************************************************************************/
#ifndef __SWD_H
#define __SWD_H

/* #define USE_STM32 */
#define USE_ESP32

#ifdef USE_STM32
#include <stdint.h>
#include "stm32f30x_gpio.h"
#elif defined( USE_ESP32 )
#include "stdint.h"
#include "driver/gpio.h"
#include "image.h"
#else
#include "define.h"
#endif

/* ERROR */
#define SWD_ERROR_OK 0
#define SWD_ERROR_PARITY 1
#define SWD_ERROR_WAIT 2
#define SWD_ERROR_FAULT 3
#define SWD_ERROR_PROTOCOL 4
#define SWD_ERROR_DEBUG_POWER 5

/* ACK responses */
#define ACK_OK     1 // 001 : 1 0 0
#define ACK_WAIT   2 // 010 : 0 1 0
#define ACK_FAULT  4 // 100 : 0 0 1

/* Address of DP read registers */
#define DP_IDCODE  0
#define DP_CTRL    1
#define DP_RESEND  2
#define DP_RDBUFF  3

/* Adressses of DP write registers */
#define DP_ABORT   0
#define DP_STAT    1
#define DP_SELECT  2

/* AHB-AP registers */
#define AP_CSW 0
#define AP_TAR 1
#define AP_DRW 3
#define AP_IDR 3  /* In bank 0xf : 0xF3 */

/* AAP registers */
#define AAP_CMD    0
#define AAP_CMDKEY 1
#define AAP_STATUS 2
#define AAP_IDR    3  /* In bank 0xf : 0xF3 */

#define AAP_CMD_ZERO      0xF0E00000
#define AAP_CMDKEY_ZERO   0xF0E00004
#define AAP_STATUS_ZERO   0xF0E00008
#define AAP_IDR_ZERO      0xF0E000FC

/* Valid values for the DP IDCODE register */
#define EFM32_DPID_1      0x2BA01477  // G, LG, GG, TG, WG
#define EFM32_DPID_2      0x0BC11477  // ZG
#define EFM32_DPID_3      0x0bc12477  // SWMD

/* Valid value for the AAP IDR register */
#define EFM32_AAP_ID    0x16e60001

/* Valid values for the AHB-AP IDR register */
#define EFM32_AHBAP_ID_1  0x24770011 // G, LG, GG, TG, WG
#define EFM32_AHBAP_ID_2  0x04770031 // ZG

/* Key which must be written to AAP_CMDKEY before
 * writing to AAP_CMD */
#define AAP_UNLOCK_KEY 0xcfacc118

/* Value to write to AIRCR in order to do a soft
 * reset of the target */
#define AIRCR_RESET_CMD 0x05FA0006

/* Bit fields for the CSW register */
#define AP_CSW_32BIT_TRANSFER   0x02
#define AP_CSW_AUTO_INCREMENT   0x10
#define AP_CSW_MASTERTYPE_DEBUG (1 << 29)
#define AP_CSW_HPROT            (1 << 25)
#define AP_CSW_DEFAULT (AP_CSW_32BIT_TRANSFER | AP_CSW_MASTERTYPE_DEBUG | AP_CSW_HPROT)

/* Powerup request and acknowledge bits in CTRL/STAT */
#define DP_CTRL_CDBGPWRUPREQ  (1 << 28)
#define DP_CTRL_CDBGPWRUPACK  (1 << 29)
#define DP_CTRL_CSYSPWRUPREQ  (1 << 30)
#define DP_CTRL_CSYSPWRUPACK  (1 << 31)

/* Commands to run/step and let CPU run.
 * Write these to DHCSR */
#define RUN_CMD  0xA05F0001
#define STOP_CMD 0xA05F0003
#define STEP_CMD 0xA05F0005

/* Flash addresses to retrieve the device unique id */
#define UNIQUE_ID_HIGH_ADDR 0x0FE081F4
#define UNIQUE_ID_LOW_ADDR  0x0FE081F0

/* AAP bit fields */
#define AAP_CMD_DEVICEERASE 1
#define AAP_CMD_SYSRESETREQ 2
#define AAP_STATUS_ERASEBUSY 1

/* Number of times to retry an SWD operation when receiving a WAIT response */
#define SWD_RETRY_COUNT 200

/* Number of times to retry the connection sequence */
#define CONNECT_RETRY_COUNT 3

/* Number of times to retry reading the AHB-IDR register when connecting */
#define AHB_IDR_RETRY_COUNT 20

/* Number of times to retry the AAP window expansion sequence (with longer and longer delays) */
#define AAP_EXPANSION_RETRY_COUNT 50

/* Number of times to retry reading the CTLR/STAT register while waiting for powerup acknowledge */
#define PWRUP_TIMEOUT 100

/* Number of times to retry reading the ERASEBUSY flag while waiting for Mass Erase (Debug Unlock) to complete */
#define UNLOCK_RETRY_COUNT 5

/* Number of times to retry reading status registers while waiting for a debug event (such as a halt of soft reset) */
#define DEBUG_EVENT_TIMEOUT 200

/* Number of times to wait for flashloader */
#define FLASHLOADER_RETRY_COUNT 1000

/* Number of times to wait for MSC operation to complete */
#define MSC_TIMEOUT 100

/* JTAG to SWD bit sequence, transmitted LSB first */
#define JTAG2SWD 0xE79E

#ifdef USE_STM32
/* USE STM32 as master, GPIO p7 as SWDIO, and GPIO p8 as SWCLK */
#define SWDIO_PIN GPIO_Pin_7
#define SWCLK_PIN GPIO_Pin_8

void SWDIO_SET_INPUT();
void SWDIO_SET_OUTPUT();
void SWCLK_SET_OUTPUT();

void SWDIO_SET();
void SWDIO_CLR();
void SWCLK_SET();
void SWCLK_CLR();

#define SWDIO_OUT(bit) {if(bit) {SWDIO_SET();} else {SWDIO_CLR();}}
uint8_t	SWDIO_IN();
#elif defined USE_ESP32
#define   __I     volatile const       /*!< Defines 'read only' permissions                 */
#define     __O     volatile             /*!< Defines 'write only' permissions                */
#define     __IO    volatile             /*!< Defines 'read / write' permissions              */

typedef struct
{
  __IO uint32_t DHCSR;                   /*!< Offset: 0x000 (R/W)  Debug Halting Control and Status Register    */
  __O  uint32_t DCRSR;                   /*!< Offset: 0x004 ( /W)  Debug Core Register Selector Register        */
  __IO uint32_t DCRDR;                   /*!< Offset: 0x008 (R/W)  Debug Core Register Data Register            */
  __IO uint32_t DEMCR;                   /*!< Offset: 0x00C (R/W)  Debug Exception and Monitor Control Register */
} CoreDebug_Type;


/** \brief  Structure type to access the System Control Block (SCB).
 */
typedef struct
{
  __I  uint32_t CPUID;                   /*!< Offset: 0x000 (R/ )  CPUID Base Register                                   */
  __IO uint32_t ICSR;                    /*!< Offset: 0x004 (R/W)  Interrupt Control and State Register                  */
  __IO uint32_t VTOR;                    /*!< Offset: 0x008 (R/W)  Vector Table Offset Register                          */
  __IO uint32_t AIRCR;                   /*!< Offset: 0x00C (R/W)  Application Interrupt and Reset Control Register      */
  __IO uint32_t SCR;                     /*!< Offset: 0x010 (R/W)  System Control Register                               */
  __IO uint32_t CCR;                     /*!< Offset: 0x014 (R/W)  Configuration Control Register                        */
  __IO uint8_t  SHP[12];                 /*!< Offset: 0x018 (R/W)  System Handlers Priority Registers (4-7, 8-11, 12-15) */
  __IO uint32_t SHCSR;                   /*!< Offset: 0x024 (R/W)  System Handler Control and State Register             */
  __IO uint32_t CFSR;                    /*!< Offset: 0x028 (R/W)  Configurable Fault Status Register                    */
  __IO uint32_t HFSR;                    /*!< Offset: 0x02C (R/W)  HardFault Status Register                             */
  __IO uint32_t DFSR;                    /*!< Offset: 0x030 (R/W)  Debug Fault Status Register                           */
  __IO uint32_t MMFAR;                   /*!< Offset: 0x034 (R/W)  MemManage Fault Address Register                      */
  __IO uint32_t BFAR;                    /*!< Offset: 0x038 (R/W)  BusFault Address Register                             */
  __IO uint32_t AFSR;                    /*!< Offset: 0x03C (R/W)  Auxiliary Fault Status Register                       */
  __I  uint32_t PFR[2];                  /*!< Offset: 0x040 (R/ )  Processor Feature Register                            */
  __I  uint32_t DFR;                     /*!< Offset: 0x048 (R/ )  Debug Feature Register                                */
  __I  uint32_t ADR;                     /*!< Offset: 0x04C (R/ )  Auxiliary Feature Register                            */
  __I  uint32_t MMFR[4];                 /*!< Offset: 0x050 (R/ )  Memory Model Feature Register                         */
  __I  uint32_t ISAR[5];                 /*!< Offset: 0x060 (R/ )  Instruction Set Attributes Register                   */
       uint32_t RESERVED0[5];
  __IO uint32_t CPACR;                   /*!< Offset: 0x088 (R/W)  Coprocessor Access Control Register                   */
} SCB_Type;


#define CoreDebug_DHCSR_S_RESET_ST_Pos     25                                             /*!< CoreDebug DHCSR: S_RESET_ST Position */
#define CoreDebug_DHCSR_S_RESET_ST_Msk     (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos)        /*!< CoreDebug DHCSR: S_RESET_ST Mask */

#define CoreDebug_DHCSR_S_HALT_Pos         17                                             /*!< CoreDebug DHCSR: S_HALT Position */
#define CoreDebug_DHCSR_S_HALT_Msk         (1UL << CoreDebug_DHCSR_S_HALT_Pos)            /*!< CoreDebug DHCSR: S_HALT Mask */

#define CoreDebug_BASE      (0xE000EDF0UL)                            /*!< Core Debug Base Address            */
#define CoreDebug           ((CoreDebug_Type *)     CoreDebug_BASE)   /*!< Core Debug configuration struct    */

/* Memory mapping of Cortex-M4 Hardware */
#define SCS_BASE            (0xE000E000UL)                            /*!< System Control Space Base Address  */
#define SCB_BASE            (SCS_BASE +  0x0D00UL)                    /*!< System Control Block Base Address  */
#define SCB                 ((SCB_Type       *)     SCB_BASE      )   /*!< SCB configuration struct           */



/* USE ESP32 as master, GPIO p0 as SWDIO, and GPIO p1 as SWCLK */
#define SWCLK_NUM 23 //GPIO2
#define SWDIO_NUM 22 //GPIO0

#define SWDIO_SET_INPUT() gpio_set_direction( SWDIO_NUM, GPIO_MODE_INPUT )
#define SWDIO_SET_OUTPUT() gpio_set_direction( SWDIO_NUM, GPIO_MODE_OUTPUT )
#define SWCLK_SET_OUTPUT() gpio_set_direction( SWCLK_NUM, GPIO_MODE_OUTPUT )

#define SWDIO_SET() gpio_set_level( SWDIO_NUM, 1 )
#define SWDIO_CLR() gpio_set_level( SWDIO_NUM, 0 )
#define SWCLK_SET() gpio_set_level( SWCLK_NUM, 1 )
#define SWCLK_CLR() gpio_set_level( SWCLK_NUM, 0 )

#define SWDIO_OUT(bit) {if(bit) {SWDIO_SET();} else {SWDIO_CLR();}}
#define SWDIO_IN() gpio_get_level( SWDIO_NUM )
#else
/* USE ADT300 as master, GPIO p0 as SWDIO, and GPIO p1 as SWCLK */
#define SWDIO_SET_INPUT() GPIO->GPIO_p0=0x20;
#define SWDIO_SET_OUTPUT() GPIO->GPIO_p0=0x00;
#define SWCLK_SET_OUTPUT() GPIO->GPIO_p1=0x00;

#define SWDIO_SET() GPIO->GPIO_OUT_SET = 0x1;
#define SWDIO_CLR() GPIO->GPIO_OUT_CLEAR = 0x1;
#define SWCLK_SET() GPIO->GPIO_OUT_SET = 0x2;
#define SWCLK_CLR() GPIO->GPIO_OUT_CLEAR = 0x2;

#define SWDIO_OUT(bit) {if(bit) {SWDIO_SET();} else {SWDIO_CLR();}}
#define SWDIO_IN() ((GPIO->GPIO_IN >> 0x0) & 0x1)
#endif // USE_STM32

// IDLE : SWDIO ouptput 0, SWCLK output 1

// SWCLK = 0, SWCLK = 1
#define SWCLK_CYCLE()   \
  SWCLK_CLR();          \
  SWCLK_SET()

// SWDIO = 1, SWDIO = 0
#define SWDIO_CYCLE()   \
  SWDIO_SET();          \
  SWDIO_CLR()

#define WRITE_BIT(bit)  \
  SWDIO_OUT(bit);        \
  SWCLK_CLR();          \
  SWCLK_SET();

#define READ_BIT(bit)   \
  SWCLK_CLR();          \
  bit = SWDIO_IN();     \
  SWCLK_SET()

void SWD_INIT();
void JTAG_to_SWD_Sequence( void );
void writeAP( int reg, uint32_t data );
void writeDP( int reg, uint32_t data );
void readAP( int reg, uint32_t *data );
void readDP( int reg, uint32_t *data );
uint32_t initDp( void );
uint32_t readApId( void );
void aapExtensionSequence( void );
void initAhbAp(void);
void SWD_TEST(void);
uint32_t readMem(uint32_t addr);
void writeMem(uint32_t addr, uint32_t data);
void haltTarget(void);
void runTarget(void);
void resetTarget(void);
void delay_us(uint32_t i);
int flash_hex();
#endif

